package routes

import (
	"eostask/eosgo"
	"fmt"
	"log"
	"net/http"
	"strconv"

	"github.com/gin-gonic/gin"
	"github.com/go-session/gin-session"
)

// 通用化响应消息格式
type RespMsg struct {
	Code string      `json:"code"`
	Msg  string      `json:"msg"`
	Data interface{} `json:"data"`
}

//code提前编码
const (
	RESPCODE_OK       = "0"
	RESPCODE_LOGINERR = "1"
	RESPCODE_PARAMERR = "2"
	RESPCODE_BLKERR   = "3"
	RESPCODE_UNKNOWN  = "4"
)

var respMapMsg = map[string]string{
	RESPCODE_OK:       "正常",
	RESPCODE_LOGINERR: "登陆失败",
	RESPCODE_PARAMERR: "参数错误",
	RESPCODE_BLKERR:   "区块链访问错误",
	RESPCODE_UNKNOWN:  "系统正在升级",
}

//统一的响应消息
func CoderspMsg(resp *RespMsg, c *gin.Context) {
	resp.Msg = respMapMsg[resp.Code]
	c.JSON(http.StatusOK, resp)
}

func Ping(c *gin.Context) {
	c.JSON(200, gin.H{
		"message": "pong",
	})
}

type UserInfo struct {
	UserName string `json:"username"`
	Password string `json:"password"`
}

// 登录服务
func Login(c *gin.Context) {
	//1. 设置响应消息
	resp := RespMsg{
		Code: "0",
	}

	//2. 延迟执行响应消息
	defer CoderspMsg(&resp, c)
	//3. 解析请求数据
	var userinfo UserInfo
	err := c.ShouldBind(&userinfo)
	if err != nil {
		log.Printf("failed to ShouldBind %v\n", err)
		resp.Code = RESPCODE_PARAMERR
		return
	}
	fmt.Printf("Login:%+v\n", userinfo)
	//4. 调用eos智能合约
	ok, err := eosgo.Login(userinfo.UserName, userinfo.Password)
	if err != nil {
		fmt.Println("failed to eos.login ", err)
		resp.Code = RESPCODE_LOGINERR
		return
	}
	//5. 反馈调用结果给前端
	if !ok {
		resp.Code = RESPCODE_LOGINERR
		fmt.Println("user or passwor err")
		return
	}
	//6. 存取session
	store := ginsession.FromContext(c)
	store.Set("username", userinfo.UserName)
	err = store.Save()
	if err != nil {
		log.Println("failed set session ", err)
		resp.Code = RESPCODE_UNKNOWN
		return
	}
}

// 注册服务
func Register(c *gin.Context) {
	//1. 设置响应消息
	resp := RespMsg{
		Code: "0",
	}

	//2. 延迟执行响应消息
	defer CoderspMsg(&resp, c)
	//3. 解析请求数据
	var userinfo UserInfo
	err := c.ShouldBind(&userinfo)
	if err != nil {
		log.Printf("failed to ShouldBind %v\n", err)
		resp.Code = RESPCODE_PARAMERR
		return
	}
	fmt.Printf("Register:%+v\n", userinfo)
	//4. 调用eos智能合约
	err = eosgo.Register(userinfo.UserName, userinfo.Password)
	if err != nil {
		fmt.Println("failed to eos.Register ", err)
		resp.Code = RESPCODE_BLKERR
		return
	}
	//5. 送积分
	err = eosgo.Mint(userinfo.UserName, 100)
	if err != nil {
		fmt.Println("failed to eos.Mint ", err)
		resp.Code = RESPCODE_BLKERR
		return
	}

}

// 任务发布服务
func IssueTask(c *gin.Context) {
	//1. 设置响应消息
	resp := RespMsg{
		Code: "0",
	}

	//2. 延迟执行响应消息
	defer CoderspMsg(&resp, c)
	//3. 解析请求数据
	var taskinfo eosgo.TaskIssueReq
	err := c.ShouldBind(&taskinfo)
	if err != nil {
		log.Printf("failed to ShouldBind %v\n", err)
		resp.Code = RESPCODE_PARAMERR
		return
	}
	fmt.Printf("Register:%+v\n", taskinfo)
	//4. 调用eos智能合约
	//读取session数据
	store := ginsession.FromContext(c)
	username, ok := store.Get("username")
	if !ok {
		fmt.Println("failed read session ")
		resp.Code = RESPCODE_LOGINERR
		return
	}
	err = eosgo.Issue(username.(string), taskinfo.Desc, taskinfo.Bonus)
	if err != nil {
		fmt.Println("failed to eos.Register ", err)
		resp.Code = RESPCODE_BLKERR
		return
	}

}

///tasklist?page=1
func TaskList(c *gin.Context) {
	//1. 设置响应消息
	resp := RespMsg{
		Code: "0",
	}
	//2. 延迟执行响应消息
	defer CoderspMsg(&resp, c)

	page := c.Query("page")
	ipage, _ := strconv.Atoi(page)

	fmt.Println("tasklist:", ipage)

	//3. eos 获取任务列表
	ibegin := (ipage - 1) * 10
	iend := ipage * 10

	tasks, err := eosgo.QueryTask(ibegin, iend)
	if err != nil {
		fmt.Println("failed to eos.QueryTask ", err)
		resp.Code = RESPCODE_BLKERR
		return
	}

	//组织一个响应数据
	data := struct {
		Total int         `json:"total"`
		Data  interface{} `json:"data"`
	}{
		Total: len(tasks),
		Data:  tasks,
	}

	resp.Data = data
}

// 任务变更服务
func UpdateTask(c *gin.Context) {
	//1. 设置响应消息
	resp := RespMsg{
		Code: "0",
	}

	//2. 延迟执行响应消息
	defer CoderspMsg(&resp, c)
	//3. 解析请求数据
	var taskinfo eosgo.TaskIssueReq
	err := c.ShouldBind(&taskinfo)
	if err != nil {
		log.Printf("failed to ShouldBind %v\n", err)
		resp.Code = RESPCODE_PARAMERR
		return
	}
	fmt.Printf("UpdateTask:%+v\n", taskinfo)
	//4. 调用eos智能合约
	//读取session数据
	store := ginsession.FromContext(c)
	username, ok := store.Get("username")
	if !ok {
		fmt.Println("failed read session ")
		resp.Code = RESPCODE_LOGINERR
		return
	}
	taskid, _ := strconv.Atoi(taskinfo.TaskID)
	//UpdateTask(from string, taskid uint64, status uint8, comment string)
	err = eosgo.UpdateTask(username.(string), uint64(taskid), taskinfo.Status, taskinfo.Comment)
	if err != nil {
		fmt.Println("failed to eos.Register ", err)
		resp.Code = RESPCODE_BLKERR
		return
	}

}

type ReqBalance struct {
	Account string `uri:"account"`
}

type BalanceResp struct {
	Account string `json:"account"`
	Amount  uint64 `json:"amount"`
}

// /balance/:account
func BalanceOf(c *gin.Context) {
	//1. 设置响应消息
	resp := RespMsg{
		Code: "0",
	}
	//2. 延迟执行响应消息
	defer CoderspMsg(&resp, c)

	var balanceReq ReqBalance
	err := c.ShouldBindUri(&balanceReq)
	if err != nil {
		resp.Code = RESPCODE_PARAMERR
		fmt.Println("failed to bind uri ", err)
		return
	}

	//3. eos 获取余额

	value, err := eosgo.BalanceOf(balanceReq.Account)
	if err != nil {
		fmt.Println("failed to eos.QueryTask ", err)
		resp.Code = RESPCODE_BLKERR
		return
	}
	balanceResp := BalanceResp{balanceReq.Account, value}

	resp.Data = balanceResp
}
